stanbol-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rupert Westenthaler <rupert.westentha...@gmail.com>
Subject Allow usage of OSGI Services without an OSGI environment (was: Future of Clerezza and Stanbol)
Date Mon, 12 Nov 2012 14:37:44 GMT
Hi,

I changed the title to separate this issue from the Clerezza/Stanbol discussion

Personally I have already tried several different things related to
this with the result that providing Service Implementations that are
also OSGI Components does only work as long as no configuration is
required (as this is the case for most Clerezza Services, but not for
typical Stanbol Services such as EnhancementEngines or Entityhub
Sites).

This is mainly because if a Service Implementation does not only
implement the @Service but also the @Component live-cycle. So usage of
the service outside of OSGI needs to mimic the live-cycle as expected
by OSGI. While this might still possible with static configurations
and dependencies it gets really complex as soon as you want/need to
dynamically bind services (e.g. by using the OSGI ServiceTracker). The
Entityhub Yard implementations follow this concept making them much
more complex as otherwise needed. In fact a lot of the problems of the
current Entityhub implementation are related to that.

An other possibility is to provide two implementations: one for OSGI
and an other one for non-OSGI usage. I used this for the
ManagedSolrServer implementations in the
o.a.stanbol.commons.solr.managed module. While this keeps complexity
for the different implementations low it does produce some level of
code duplications. So it is by far not an optional Solution. Because
of that I third an third approach when implementing ManagedSites for
the Entityhub [1].

The main Idea is to separate the OSGI Component (@Component
annotation) and the OSGI Service (@Service annotation) for any service
that requires any kind of configuration. So typically you end up with
two classes

1. The service implementation: This is a POJO, created via the
constructor and configured by parsing a configuration (or simple by
calling some setter methods). It does not follow any workflow (such as
activate, deactivate). Users are free to use it outside of OSGI, but
they are responsible themselves to set an appropriate configuration
and depending services.

2. The OSGI Component: A Class in a private package annotated with the
@Component and @Property annotations. During @Activate it
reads/validates the configuration. In the case that it also depends on
other services it might get those statically via @Reference
annotations or dynamically by using ServiceTracker created during
activation. As soon as all dependencies are available it instantiates
and configure the service implementation (1) and register it as OSGI
service by using the BundleContext of the @Component. When an Service
becomes unavailable or @Deactivate is called it needs unregisters the
Service instance (1).

Non OSGI users can use the POJO service classes in a similar way as
the OSGI Components use them during their life-cycle.

But also when running within an OSGI environment this design has two
major advantages:

* it provides a clear abstraction between the Service Architecture and
the Configuration Unit. As an example for configuring a Entityhub
Managed Site a user currently needs to configure three Services (Yard,
Cache and the ReferencedSite). With the above approach one can provide
user level components (e.g. a "Full Local Cache" - SolrYard, Cache and
ReferencedSite; a "Cached Linked Data Resource" - ClerezzaYard, Cache,
ReferencesSite with configured CoolURI/SPARQL endpoint; ...) while
still keeping the fine granular service infrastructure.
* it avoid unsatisfied Components because of unavailable services.
While this is an expected behavior in case a Singleton (such as the
ConfigurationAdmin service, Clerezza TcManager ...) is not available,
but if the user refers an service instance (e.g. by configuring name
of the SolrCore used for lookup Entities) than he would like that his
configuration - the component - activates and starts listening for the
referenced service to become available - rather than going in the
"unsatisfied" state (what would require the user to manually activate
the service after all dependencies become available).

While there is no immediate plan to completely switch to the described
design it is definitely plant to use it for new and refactored
components.
For the Entityhub this will most likely happen when adapting the
2-layerd design as currently implemented for the Contenthub
(STANBOL-471).
For the Stanbol Enhancer it would make sense to switch to this design
for EnhancementEngines that do depend on other services (e.g.
entity-linking engines that require the Stanbol Entityhub or Engine
that depend on user/pwd configurations for External service).

Also NOTE that this does not cover all aspects required to allow usage
of Stanbol components without an OSGI environment. For that one needs
also to find solutions for all **Manager style services. It tries only
to outline a solution to decouple the configuration management and
life-cycle assumptions of OSGI from the actual service implementation
so that it is possible to use those services in environment with
different life-cycle and configuration facilities.

best
Rupert Westenthaler

[1] http://svn.apache.org/repos/asf/stanbol/trunk/entityhub/site/managed/
    the service Implementation:
org.apache.stanbol.entityhub.site.managed.impl.YardSite
    the OSGI component
org.apache.stanbol.entityhub.site.managed.ManagedSiteComponent


On Mon, Nov 12, 2012 at 2:15 AM, Peter Ansell <ansell.peter@gmail.com> wrote:
> On 12 November 2012 09:59, Reto Bachmann-Gm├╝r <reto@apache.org> wrote:
>> Hi Peter and all,
>>
>> Good to read about your experiments.Just a first comment:
>>
>> In addition, I did not want to use OSGI, so I had to make changes in
>>> many cases to allow a completely programmatic instantiation of
>>> components, as some fields were left private with no mutator method
>>> and in some cases no public contructor that could be used to populate
>>> the field programmatically. For all of the good that OSGI may provide
>>> for otherwise complex systems, it is not good Java software
>>> engineering to make fields private.
>>>
>>
>> The clerezza.rdf package should all be usable withouth OSGi. OSGi cannot do
>> magic and set private fields, the compiled classes do have bind and unbind
>> methods for the private fields, these methods are added by the maven felix
>> scr-plugin.  For locating dependencies outside OSGi the META-INF/services
>> method is used so that for example one can add a serializitaion provider
>> seimply by adding it to the classpath without requiring and manual binding.
>
> Sorry, I was under the impression that OSGi could actually do Java
> reflection magic to inject dependencies directly into private fields
> based on annotations without having any alternative method of setting
> the field for regular plain old java users. :)
>
> In general I would like if OSGi classes that currently rely on
> bind/unbind, still offered public mutator methods and a public
> initialise/deinitialise method for any work that needs to be done
> after using the mutator methods. The bind/unbind methodology from
> memory when I was working on Clerezza/Stanbol, seemed to require that
> all of the mutators were run immediately and the initialise was
> automatically run, without offering any other possible sequence.
>
> Additionally, offering public mutators and a public initialise method
> gives the added benefit of compile-time typesafety for plain old java
> users, which a bind method taking a Dictionary<String, Object>
> parameter does not provide.
>
> In addition, from memory I think some of the bind methods were
> protected, and not public, which means they are not directly
> accessible, without resorting to using reflection or subclassing just
> to be able to call bind.
>
> I use META-INF/services heavily in my projects, and I rely on it when
> using Sesame and with my extensions to OWLAPI. I extended OWLAPI to
> use Sesame META-INF/services dependencies to find
> serialisation/parsing providers for OWLAPI based on the Sesame
> parser/writer services that are available on the classpath. However, I
> always try to make sure that the use of the automatically populated
> service registries is optional, so that users can populate their own
> registries from scratch using purely programmatic methods, and they do
> not have to resort to modifying global singleton registries as one
> does when using Jena.
>
> The services that I register in META-INF/services are always factories
> based on interfaces, so that dependencies can be passed into type-safe
> java "createServiceInstance" methods when creating instances of the
> service using the factory instance. This means that it does not matter
> if the java.util.ServiceLoader loads classes in a different order, as
> the actual objects are created from the factories explicitly by users,
> with or without a key to specify which instance of the service they
> require/prefer.
>
> Cheers,
>
> Peter



-- 
| Rupert Westenthaler             rupert.westenthaler@gmail.com
| Bodenlehenstra├če 11                             ++43-699-11108907
| A-5500 Bischofshofen

Mime
View raw message