Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Equinox » declarative services dependency injection questions
declarative services dependency injection questions [message #104128] Sun, 20 January 2008 12:07 Go to next message
David Donohue is currently offline David DonohueFriend
Messages: 104
Registered: July 2009
Senior Member
(Reposting to show the below XML, sorry)

Hello,
I am having a perplexing problem, that DS is not working as I expected.

I have a bundle org.bundleA, which declares both a service and a component.

<?xml version="1.0"?>
<component name="ComponentA" immediate="true">
	<implementation class="org.my.ComponentA"/>
	<service>
		<provide interface="org.my.IComponent"/>
	</service>
</component>

<?xml version="1.0"?>
<component name="ServiceA" immediate="true">
	<implementation class="org.my.ServiceA"/>
	<reference name="IComponent"
		interface="org.my.IComponent"
		bind="addComponent"
		cardinality="1..n"
		policy="dynamic" />
</component>


I test this in the bundle's Activator.

public void start(BundleContext context) throws Exception {
ServiceA serviceA = new ServiceA();
System.out.println("Created ServiceA with " + serviceA.countComponents() + " components");
}

and I get this output
Created ServiceA with 0 components
Running ServiceA.addComponent()

So my first question is: is this the order in which this should happen? Note that the componets do not seem to be available until later (too late).

So I move the above start method to a 2nd bundle's Activator instead. And here is the output

Created ServiceA with 0 components

Apparently the DS did not kick in and inject the dependencies when I create a ServiceA object from a 2nd bundle.

Second question: Is this the expected behavior? Can only the bundle which declares the component and/or service use them?

Thanks!
David
Re: declarative services dependency injection questions [message #104156 is a reply to message #104128] Mon, 21 January 2008 03:26 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: ronbermejo.nospamm.com

Hello David!

David wrote:

> (Reposting to show the below XML, sorry)

> Hello,
> I am having a perplexing problem, that DS is not working as I expected.

> I have a bundle org.bundleA, which declares both a service and a component.

>
> <?xml version="1.0"?>
> <component name="ComponentA" immediate="true">
> 	<implementation class="org.my.ComponentA"/>
> 	<service>
> 		<provide interface="org.my.IComponent"/>
> 	</service>
> </component>

> <?xml version="1.0"?>
> <component name="ServiceA" immediate="true">
> 	<implementation class="org.my.ServiceA"/>
> 	<reference name="IComponent"
> 		interface="org.my.IComponent"
> 		bind="addComponent"
> 		cardinality="1..n"
> 		policy="dynamic" />
> </component>
> 


> I test this in the bundle's Activator.

> public void start(BundleContext context) throws Exception {
> ServiceA serviceA = new ServiceA();
> System.out.println("Created ServiceA with " + serviceA.countComponents()
+ " components");
> }

> and I get this output
> Created ServiceA with 0 components
> Running ServiceA.addComponent()

> So my first question is: is this the order in which this should happen?
Note that the componets do not seem to be available until later (too late).

Since you instantiated the ServiceA object itself, DS will not inject the
dependency for you. It will only inject dependencies for components it
created..

Also, the bundle must be started before any components are enabled. Hence,
you do not see the "Running ServiceA.addComponent()" until after the
bundle is activated.

Hth!
Ron
Re: declarative services dependency injection questions [message #104196 is a reply to message #104156] Mon, 21 January 2008 12:48 Go to previous messageGo to next message
David Donohue is currently offline David DonohueFriend
Messages: 104
Registered: July 2009
Senior Member
Ron,
Thanks for your reply! I am confused. If DS only injects dependencies for components that it created, how can I make use of it? How can I use DS to create an object that is injected with all its reference components?
Best,
David
Re: declarative services dependency injection questions [message #104209 is a reply to message #104196] Mon, 21 January 2008 14:22 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: benedikt.arnold.beyondsoft.de

Hi David!

Take a look at factory components as described by the OSGi specification.

Greetings,
Ben


"David" <dd@daviddonohue.com> schrieb im Newsbeitrag
news:3908903.103061200919746782.JavaMail.root@cp1.dzone.com...
> Ron,
> Thanks for your reply! I am confused. If DS only injects dependencies
> for components that it created, how can I make use of it? How can I use
> DS to create an object that is injected with all its reference components?
> Best,
> David
Re: declarative services dependency injection questions [message #104281 is a reply to message #104209] Tue, 22 January 2008 03:28 Go to previous messageGo to next message
David Donohue is currently offline David DonohueFriend
Messages: 104
Registered: July 2009
Senior Member
Ben,
Thanks! I have been backwards & forwards through that difficult chapter on declarative services in the OSGi Service Platform Service Compendium. I am still quite confused. However I might have made progress.

Here is my latest code


<!-- ComponentA.xml -->
<?xml version="1.0"?>
<component name="ComponentA" factory="org.my.factory">
	<implementation class="org.my.ComponentA"/>
	<service>
		<provide interface="org.my.IComponent"/>
	</service>
</component>
 

<!-- ServiceA.xml -->
<?xml version="1.0"?>
<component name="ServiceA" immediate="true">
	<implementation class="org.my.ServiceA"/>
	<reference name="ComponentFactory"
		interface="org.osgi.service.component.ComponentFactory"
		bind="addComponentFactory"
		target="(component.factory=org.my.factory)"
   />
</component>


So now I get this output

Created ServiceA with 0 components
osgi> Running ServiceA.addComponentFactory()...

I learned that in order to use ServiceA from a different bundle from which it is declared, I need to declare it (again) in that 2nd bundle. So I copy the above ServiceA.xml to my 2nd bundle and also add this to MANIFEST.mf

Service-Component: OSGI-INF/ServiceA.xml

Overall it seems that DS would benefit from a static method that any class in any bundle can call, analogous to what we have in Equinox extensions & extension points:
Platform.getExtensionRegistry();

Thanks again,
David
Re: declarative services dependency injection questions [message #104300 is a reply to message #104281] Tue, 22 January 2008 07:41 Go to previous messageGo to next message
Danail Nachev is currently offline Danail NachevFriend
Messages: 110
Registered: July 2009
Senior Member
David wrote:
> Ben,
> Thanks! I have been backwards & forwards through that difficult chapter on declarative services in the OSGi Service Platform Service Compendium. I am still quite confused. However I might have made progress.
>
> Here is my latest code
>
>
>
> <!-- ComponentA.xml -->
> <?xml version="1.0"?>
> <component name="ComponentA" factory="org.my.factory">
> 	<implementation class="org.my.ComponentA"/>
> 	<service>
> 		<provide interface="org.my.IComponent"/>
> 	</service>
> </component>
>  
> 
> <!-- ServiceA.xml -->
> <?xml version="1.0"?>
> <component name="ServiceA" immediate="true">
> 	<implementation class="org.my.ServiceA"/>
> 	<reference name="ComponentFactory"
> 		interface="org.osgi.service.component.ComponentFactory"
> 		bind="addComponentFactory"
> 		target="(component.factory=org.my.factory)"
>    />
> </component>
> 

>
> So now I get this output
>
> Created ServiceA with 0 components
> osgi> Running ServiceA.addComponentFactory()...
>
> I learned that in order to use ServiceA from a different bundle from which it is declared, I need to declare it (again) in that 2nd bundle. So I copy the above ServiceA.xml to my 2nd bundle and also add this to MANIFEST.mf
>
> Service-Component: OSGI-INF/ServiceA.xml
>
> Overall it seems that DS would benefit from a static method that any class in any bundle can call, analogous to what we have in Equinox extensions & extension points:
> Platform.getExtensionRegistry();
>
> Thanks again,
> David

Hi, David

It shouldn't be require to declare a component in the bundles, where you
use them. There are two types of components: immediate and ordinary.
Immediate are components which are activated whenever their requirements
are satisfied. The ordinary components are registered as OSGi service
factories (they are available in the OSGi service factory, but are not
activated until a service is requested), when they have their
requirements (references) satisfied. When someone calls getService() for
the component's service, the component is activated (it's class is
instantiated, its references are provided through bind methods, if
present and its activate() method is called, if provided).

Using component factories is a specific need, which I'm not sure you
need it (However, it should work.) I suggest that you return to the
previous way of doing the things. However, change your code to not
instantiate the components. DS will do it for you.

How this is used? The idea is to let DS handle all service handling for
you. So, instead of having multiple ServiceTracker() objects, which
listens for services, and registers another service when its
requirements are available (all required service are registered), you
let the DS do the dirty work. It will register services for all your
components which has <provide> tag and have fulfilled their requirements
(references). If the component is declared immediate, it will call its
activate() method immediately. If it is not, its activate() is called
when another component (or bundle through OSGi service registry) get a
reference to the component's service. Immediate components can be used
as a drivers - components which does some initialization and should not
be lazy. For example, if you need to do something upon startup (opening
ports (for servers), doing some initialization with external entities
and so on). You will use immediate component. If your component can wait
before it is activated (for example, some service used once per year:)

If you need to do some initialization of the component, you implement
activate() method. If your service can act without initialization, you
just implement the services methods as declared in the interface of the
component. (IMHO, doing lazy initialization of the component is not very
useful, because DS usually takes care that your component is activated
at the very last moment, so it is almost sure, that after the component
is activated, it will be used, so it is better to move your
initialization code in the activate() method instead of polluting your
main code with it)

Both DS and Extension Registry provides ways to declare relationships
between different components and let them control when they are loaded.
However, they differ in the means of which this is accomplished and
their flexibility (DS is a little more flexible, however, extension
registry permits you to specify more declarative information, which
suits Eclipse architecture very well).

If you haven't read, here is a great tutorial on OSGi, including DS:

http://neilbartlett.name/blog/osgi-articles/

I wonder, where the "Created ServiceA with ... components" dump is
located in the code (can you provide us with the code too)?
Re: declarative services dependency injection questions [message #104323 is a reply to message #104300] Tue, 22 January 2008 12:40 Go to previous messageGo to next message
David Donohue is currently offline David DonohueFriend
Messages: 104
Registered: July 2009
Senior Member
Ben?,

Thanks for the lucid explanation! Most helpful! Here is my code, in the bundle's Activator class:

public void start(BundleContext context) throws Exception {
ServiceA serviceA = new ServiceA();
System.out.println("Created ServiceA with " + serviceA.countComponents() + " components");
}

I have read Neil Bartlett's fine articles on OSGi & DS.

One issue I have is that I would like "plugin contributors" to my application to make use of these services without requiring them to have a BundleActivator class and without requiring them to pass around a reference to BundleContext. This can be cumbersome, since my OSGi app is a web server, and much code is getting executed in Servlets or other objects called from servlets. So this code is far removed from the BundleContext. Again, a static method like that provided in Eclipse Extensions is handy in that setting.

Is there a way for me to use DS to behave like a plug-in environment, without requiring passing around BundleContext instances or getting ServiceTracker instances?

Thanks again!
David
Re: declarative services dependency injection questions [message #104331 is a reply to message #104323] Tue, 22 January 2008 13:22 Go to previous messageGo to next message
Danail Nachev is currently offline Danail NachevFriend
Messages: 110
Registered: July 2009
Senior Member
You won't require any BundleContext or activator. As a matter of fact,
you can do even without ComponentContext, unless you need to be notified
when your component is activated. Just implement your component, add the
needed bind/unbind methods and you are ready to go.

One clarification, I wish to make, is that you don't require
BundleContext and ServiceTracker. DS does exactly this, remove the need
to handle BundleContexts and ServiceTrackers, you deal only with
components, which dependencies are specified in declarative way.

Your contributors doesn't need to know about BundleContext and/or
BundleActivator. They just declare the components in XML document in the
bundle and implement the proper logic.

There are generally two cases where components interact:
1) component A use component B (and depend on it) (http server (A) use
log service (B)) - nothing special, just specify that component A
depends on component B
2) component A extend component B (http server (B) is extended with
servlets (A)) - this case is similar to the extension registry.
component B need to specify that it depends on component A (so, whenever
a component A is made available, it will be passed to component B, which
then can make use of it). The extension registry works exactly the same
way, however, there you need to get a reference to the extension
registry, ask for extensions for specific extension point and then
process the information. In DS way, you don't need to ask for extension
registry and then for extensions, etc. Everything is passed
automatically to you.

Of course, there might be (and there are) other ways of using DS and I
don't think that I have covered them all:)

In your case, your contributors will declare references to the services
you provide and you are set to go. Nothing special, nothing fancy.

DS is essentially dependency injection model based on OSGi Service
Registry. Nothing more.

How will help you, if DS behaves more like the Extension Registry, I
can't see what exactly are you trying to accomplish?

Danail

David wrote:
> Ben?,
>
> Thanks for the lucid explanation! Most helpful! Here is my code, in the bundle's Activator class:
>
> public void start(BundleContext context) throws Exception {
> ServiceA serviceA = new ServiceA();
> System.out.println("Created ServiceA with " + serviceA.countComponents() + " components");
> }
>
> I have read Neil Bartlett's fine articles on OSGi & DS.
>
> One issue I have is that I would like "plugin contributors" to my application to make use of these services without requiring them to have a BundleActivator class and without requiring them to pass around a reference to BundleContext. This can be cumbersome, since my OSGi app is a web server, and much code is getting executed in Servlets or other objects called from servlets. So this code is far removed from the BundleContext. Again, a static method like that provided in Eclipse Extensions is handy in that setting.
>
> Is there a way for me to use DS to behave like a plug-in environment, without requiring passing around BundleContext instances or getting ServiceTracker instances?
>
> Thanks again!
> David
Re: declarative services dependency injection questions [message #104386 is a reply to message #104331] Wed, 23 January 2008 08:59 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: benedikt.arnold.beyondsoft.de

Hi David!

As Danail mentioned you don't need the Bundle- or ComponentContext. You
could inject your debendencies into your servlet. I' ve done it like this:
1. Create a Component for your servlet.
2. Inject erverything you need + the HttpService into it and in the
bind-method for the http service let the servlet register itself

Here is an extract of the component declaration:
<?xml version="1.0"?>

<component name="phoneservlet" immediate="true">

<implementation class="de.beyondsoft.voipconf.httpdelivery.Servlet" />

<reference name="org.osgi.service.log.LogService"
interface="org.osgi.service.log.LogService" cardinality="1..1"
bind="bindLogService" unbind="unbindLogService" />

<reference name="org.osgi.service.http.HttpService"
interface="org.osgi.service.http.HttpService" cardinality="1..1"
bind="bindHttpService" unbind="unbindHttpService" />



</component>

The bind- and unbind-method for the http service defined in your servlet
could look like this:
protected void bindHttpService(HttpService http) throws ServletException,

NamespaceException {

http.registerServlet(ALIAS, this, null, null);

}


protected void unbindHttpService(HttpService http) {

http.unregister(ALIAS);

}

Greetings,

Ben
Re: declarative services dependency injection questions [message #104400 is a reply to message #104386] Wed, 23 January 2008 12:04 Go to previous message
David Donohue is currently offline David DonohueFriend
Messages: 104
Registered: July 2009
Senior Member
Danail & Ben,
Great stuff, many thanks for the clear example. Will try to follow this design pattern exactly.
Best,
David
Previous Topic:Blocking javax.xml.bind in JDK1.6
Next Topic:PDEs RemotePluginTestRunner has a problem loading a test class
Goto Forum:
  


Current Time: Sun Nov 23 01:26:15 GMT 2014

Powered by FUDForum. Page generated in 0.02072 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software