On 05/25/2015 10:02 AM, Peter Kriens wrote:
I tend to agree (actually rather violently) with Neil: ‘new’ for private 
objects is perfectly OK in a bundle.

Why did DI frameworks got so popular? I think this was mostly because 
applications had grown so large and constituted of so many different parts that 
you needed central control to keep things apart and control their 
initialization in the right order.

Now back to OSGi. First and foremost, you no longer (should!) have a monolith. 
A good bundle is cohesive. This means that everything in that bundle belongs 
together. So why should you make a mock if that thing is already coupled? There 
is no use to take the cost of abstracting because if anything changes, all its 
dependencies are together? I.e. the compiler will immediately tell you if you 
use things wrong. So by using ’new’ I get the benefit of readability, no magic, 
compiler checks, navigation in the IDE, and full refactoring. Best of all, no 
XML programming! For me one of the best things about OSGi is that the 
components are often so simple because they look like plain old java.

Usually, in engineering, the ’truth’ is rarely at the extremes. Imho, DS found the 
right balance between external (dynamic) dependencies -> injection, for the 
rest plain old java since injection does not really provide you with anything but 
familiarity.

And if you really absolutely want injection … just use Guice or another DI 
container inside your component?

I guess we'll just have to "agree to disagree" here. Maybe we work on different kinds of code.

I also am not a big fan of xml-based DI frameworks. Guice is properly type-safe, ie works fine with refactoring and provides compile-time safety plus the benefits I mentioned in my original email. And as I also mentioned in my original email, the primary use for DI is for injecting appropriate _singleton_ objects, not things that can be created with "new".

Blueprint has always supported full DI without needing to expose internal singletons as services in the global registry. It appears that iPojo's "composites" also support this. And it appears that the OSGi Subsystem service also supports "scoping" of services, but is rather heavy-weight to use and not really intended for this use-case.

Using Guice or similar isn't a good option due to the lack of support for the OSGi lifecyle. Imagine a bundle that wishes to create the following objects:

* exported service S1 which requires internal singleton T
* exported service S2 which also requires internal singleton T
* internal singleton T requires various other objects, including an instance of V
* and V requires imported service S5

It is not possible to use Guice to create T because it indirectly requires service S5 from the service registry. T (and V) should have a proper lifecycle, ie be created when S5 is available and be removed when S5 is no longer available. Guice cannot do that. And this is a _common usecase_.

In order for lifecycles to work properly, all objects (S1, S2, T, V, and anything else) should be tracked via a service registry - as DS, DM, etc do. That way, removal of a service triggers a "cascade" of removals of things that depend on it. The only thing I'm looking for is a way for internal objects T, V, etc to not be visible _container-wide_.

Thanks to the replies on this list, it appears that DS and DM cannot do this - ie those who wish to use any kind of DI within bundles need to either: (a) use DS or DM and accept that internal singletons must be published globally;
(b) use Blueprint or iPojo;
(c) use a workaround.

In iPojo, the <composite> element in a config file creates a new service-registry which is independent of the global one. A nested <subservice> tag then imports a service from the global registry into the new one. And a nested <provides> tag exports a service from the new one into the global one. This approach is slightly different to the one I suggested earlier could be possible within DM or DS, but has the same effect. Note that DM also uses the word "composite" but that appears to be a different thing.

Another less elegant approach I have considered is to use the ConditionalPermissionAdmin service; a service intended for local use within a bundle could be tagged with a property "service.local" or similar, and a rule could be added to ConditionalPermissionAdmin to make any service with that property visible (get-permission) only to the bundle that published it. That solves the "privacy" issue, though possibly has performance implications.

Thanks to all for your feedback.

Regards,
Simon

On 22 mei 2015, at 10:12, Simon Kitching <si...@vonos.net> wrote:

Thanks Pierre and Neil for your replies!

To avoid splitting this thread, I'll also reply to Neil's email here.

I agree with Neil completely about the Blueprint lifecycle (ugly). I much 
prefer the DS lifecycle management - but miss the ability in DS or DM to manage 
bundle-private objects. I find it interesting that OSGi has solved the problem 
of a global class namespace (via Export-Package), but has then created a single 
global service namespace.

Regarding the use of "new":

(a) It would be nice to share code between OSGi and non-OSGi environments. In 
non-OSGi environments, use of dependency injection (rather than explicit use of 
new) is wide-spread.

Do you not have problems when trying to share code between OSGi and non-OSGi 
environments?

(b) DI isn't usually used to inject things that can be created with "new". Instead, it is predominantly used 
to inject singleton objects that are used by many other objects. As an example, a common _cache_ may be injected, or a 
serialization-helper. The alternative to DI in this case is not "new", but instead the old "static 
singleton" pattern, or lookup via JNDI or similar. Or to retrieve the object from the OSGi service registry - but 
that leads to "polluting" of the global service registry which I am concerned about.

Do you not have problems when sharing a "bundle-private" object between 
multiple DS-managed objects?

(c) One major motivation for using DI is to support unit testing. When a class uses DI 
properly, then a unit test can instantiate that class with mocks for the various other 
objects it interacts with. The test can then verify that the class under test interacts 
with mock objects as expected. It can also emulate various failures in the mocked 
systems, eg returning error-codes or throwing exceptions. When a class uses 
"new" to instantiate a helper object, no mocking of the external class is 
possible.

When you use "new" in your code, does this not cause you problems with unit 
test coverage?

Because of the above, I don't currently see using "new" as an alternative to DI 
for wiring up objects inside a bundle.
OSGi defines only one service registry, accessible by any bundles. iPOJO splits 
these two interaction types. Instances receive an iPOJO Bundle
Context delegating bundle-related methods to the "regular" bundle context, and 
service-related methods to a service context. This service context
can access to the OSGi service registry or to a new one. Each composition 
instances have a service registry.
I'm not so concerned about "too many services in the registry" as I am about 
*bundle-private* services being present in the global registry.

Do you see any reason why DM and DS could not adopt the same approach as iPojo, 
ie a per-composition (or at least per-bundle) service registry? I could imagine 
the following enhancement for DS:
  <component>
    <service>
      <provide interface="..." scope="local"/>
where the new "scope" attribute indicates that this particular component should be 
placed into the per-bundle service registry rather than the global one. All <reference> 
elements would then look first in the per-bundle registry before looking in the global one.

For DM, something similar could be done with:
  createComponent().setInterface("..", Scope.LOCAL)

Maybe another solution is to take advantage of felix-dm's ability to define "dependency 
handlers", and add another kind of dependency called "local" or similar? [as 
suggested by Karl Pauls in the email pointed out by Pierre]

All opinions gratefully accepted!

Regards, Simon

On 05/22/2015 08:34 AM, Pierre De Rop wrote:
Hello Simon,

DM, like DS does not implement a private service registry to intra-bundle
components (well, except for optimized DM filter indices, but this is
another story).

I think Ipojo do support what you are describing, but I prefer to let other
people respond about this since I'm not enough experienced in iPojo. See
[1] about this, which comes from the osgi mailing list.

Now, I tend to agree with Neil, and intra-bundle private services can
simply be instantiated with the "new" keyword.
Alternatively, with DM, you can also use a composition of service
components: this allows you to:

- only register one single service for the bundle in the OSGi service
registry (or even only one DM component if it does not provide any services
at all, but just needs to define some dependencies to external services
(outside the bundle).

- and define a composition of objects that will get injected with the
external services.
For example, you can take a look at [2] for a concrete sample code of a
bundle which defines a component that is instantiated using a
"CompositionManager" pojo that is first injected with a configuration. And
from the configuration, the pojo may then create an implementation for the
service that the bundle provides, and also, some other pojo objects that
are part of the service implementation. The pojos will then be injected
with all the external service dependencies defined in the Activator (either
using field injection of bind method callbacks).

There is also another example which does not use a Factory, but only a
service composition in [3].

Finally, I would like to say that it's a not a real problem to have many
services registered in the Osgi service registry.
Registering services is cheap. And DM now supports an actor based thread
model which allows to activate, manage, and bind service components
concurrently, using a shared threadpool, and there is no startup time
degradation (I often start around 20000 services and my Felix Framework
starts in few of seconds). The new thread model is descriped in [4].

Also, regarding service diagnostics, even if you have thousands of micro
services registered in the OSGi registry, then DM gogo shell supports
advanced commands that allows you to quickly make some diagnostics (like
loop detection, missing service root causes, service lookup using filters,
etc ...).

[1] https://mail.osgi.org/pipermail/osgi-dev/2014-February/004310.html
[2]
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/compositefactory/
[3]
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/composite/
[4]
http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/thread-model.html

kind regards;
/Pierre

On Thu, May 21, 2015 at 4:52 PM, Simon Kitching <si...@vonos.net> wrote:

Hi,

In blueprint it is possible to define arbitrary objects (beans) which are
not published to the service registry but nevertheless can be injected into
other beans.

AFAICT, in both declarative-services and felix-dm, the only objects that
can be injected are references to services from the OSGi registry. Is this
correct?

I understand that with DS and DM, components follow the standard OSGi
lifecycles, in contrast to the Blueprint approach of "hiding" the
lifecycle. In particular, in DS and DM when a component's mandatory
dependency is deregistered then the component is also deregistered (which
can cascade further). And the kind of tracking of dependencies required to
make this happen is exactly what a service registry does.

However it's common for a bundle to have objects which are purely internal
implementation details of the bundle, and are not for external use. Yet as
far as I can see, in order to manage them with DS or DM, such internal
objects need to be published into the global service registry - just to be
able to then inject them back into components in the same bundle.

Have I misunderstood something?

Thanks,
Simon

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org

Reply via email to