Multiple Component Instances with OSGi

284 views
Skip to first unread message

Paul F Fraser

unread,
Jul 28, 2015, 2:01:23 AM7/28/15
to bndtool...@googlegroups.com
Hi,

Ref : Neil Bartlett blog http://njbartlett.name/2010/07/19/factory-components-in-ds.html
I have not been able to reliably create instances using this technique.
The following code does not seem to create the desired instance. Where am I going wrong?
Is it something to do with lazy loading?

==========================================================================
package instance.maker;

import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;

import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;

import aQute.bnd.annotation.component.Activate;
import aQute.bnd.annotation.component.Component;
import aQute.bnd.annotation.component.Deactivate;
import aQute.bnd.annotation.component.Reference;

@Component(immediate = true)
public class InstanceMaker {

private ConfigurationAdmin configAdmin;

@Activate
public void startup(ComponentContext ctx) throws InvalidSyntaxException, IOException {

String pid = "mycomponent.MyComponent";
Configuration config = configAdmin.createFactoryConfiguration(pid);

Dictionary props = new Hashtable();
props.put("name", "My Name");

config.update(props);
System.out.println("InstanceMaker : startup");
}

@Deactivate
public void shutdown(ComponentContext ctx) {

System.out.println("InstanceMaker : shutdown");
}

@Reference
public void setConfigAdmin(ConfigurationAdmin configAdmin) {
this.configAdmin = configAdmin;
System.out.println(" InstanceMaker : setConfigAdmin");
}

public void unsetConfigAdmin(ConfigurationAdmin configAdmin) {
this.configAdmin = null;
System.out.println("InstanceMaker : unsetConfigAdmin");
}

}


==================================================================================
package mycomponent;

import java.util.Map;

import aQute.bnd.annotation.component.Activate;
import aQute.bnd.annotation.component.Component;

import aQute.bnd.annotation.component.ConfigurationPolicy;

@Component(immediate=true,configurationPolicy = ConfigurationPolicy.require)
public class MyComponent implements IMyComponent {


@Activate
public void activate(Map<String, String> config) {
System.out.println("MyComponent : activate");
String name = config.get("name");
System.out.println(name);
}



public void doSomething() {
System.out.println("Doing Something now");
}
}
=======================================================================================


Regards

Paul Fraser

Marc Schlegel

unread,
Jul 28, 2015, 6:10:55 AM7/28/15
to bndtools-users, pa...@a2zliving.com
Just to share another post which uses a ComponentFactory instead of ConfigAdmin to get around the singleton-issue.
In my case I needed one service to be created per user-session in order to store some data necessary for communication with a host. 


regards
Marc

David Jencks

unread,
Jul 28, 2015, 11:05:20 AM7/28/15
to bndtool...@googlegroups.com
I don’t see what is wrong. If you turn up felix ds logging to debug you can probably see what is happening and why. As well as making whatever logging framework you are using show debug messages, you need to configure ds with ds.loglevel=debug; you can do this with a configuration for DS but it’s usually easier to supply it as a framework property.

You might also check that the ds xml is getting generated the way you expect by looking into the bundle….

hope this helps
david jencks

> On Jul 28, 2015, at 2:01 AM, Paul F Fraser <pa...@a2zliving.com> wrote:
>
> Hi,
>
> Ref : Neil Bartlett blog http://njbartlett.name/2010/07/19/factory-components-in-ds.html
> I have not been able to reliably create instances using this technique.
> The following code does not seem to create the desired instance. Where am I going wrong?
> Is it something to do with lazy loading?
>
> ==========================================================================
> package instance.maker;
>
> import java.io.IOException;
> import java.util.Dictionary;
> import java.util.Hashtable;
>
> import org.osgi.framework.InvalidSyntaxException;
> import org.osgi.service.cm.Configuration;
> import org.osgi.service.cm.ConfigurationAdmin;
> import org.osgi.service.component.ComponentContext;
>
> import aQute.bnd.annotation.component.Activate;
> import aQute.bnd.annotation.component.Component;
> import aQute.bnd.annotation.component.Deactivate;
> import aQute.bnd.annotation.component.Reference;
> show
> --
> You received this message because you are subscribed to the Google Groups "bndtools-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to bndtools-user...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Paul F Fraser

unread,
Jul 29, 2015, 12:19:20 AM7/29/15
to bndtool...@googlegroups.com
Hmm,

Neil Bartlett draft book page 220
"An additional and very compelling feature of DS when it is used to publish services is its
ability to defer creation of the component
until its service is actually used by a client."


Adding this code to "class InstanceMaker" and it works. This code is using the instance and it is
created as expected.

@Reference(type = '*')
public void setInstance(MyComponent comp) {
instances.add(comp);
System.out.println(" InstanceMaker : new Instance name = " + comp.name);
}

public void unsetInstance(MyComponent comp) {
instances.remove(comp);
System.out.println(" InstanceMaker : setConfigAdmin");
}

Paul

Paul F Fraser

unread,
Jul 29, 2015, 9:36:00 PM7/29/15
to bndtool...@googlegroups.com
Hi Again,

1/ Is it possible/permissible to create a component from within a component instance created from
multiple component technique under discussion?

I have tried to do this but the instance does not seem to be instantiated.

2/ After config.update(props) is executed, what is the usual way(s) to get the instance reference
other than the @Reference method shown?

@Reference(type = '*')
public void setInstance(MyComponent comp) {
instances.add(comp);
System.out.println(" InstanceMaker : new Instance name = " + comp.name);
}

public void unsetInstance(MyComponent comp) {
instances.remove(comp);
System.out.println(" InstanceMaker : setConfigAdmin");
}

Paul

David Jencks

unread,
Jul 30, 2015, 12:58:53 AM7/30/15
to bndtool...@googlegroups.com
I don’t understand your question. Could you be more explicit about how many components you want and what you want each one to do and what references you want between them?

You’ll only be able to get the instance if it is registered as a service (e.g. it implements an interface or you have explicitly specified the services you want to register it under in the @Component annotation). As an OSGI service, there are lots of ways to get it: directly querying the SerivceRegistry, a ServiceTracker, blueprint, DS reference, DM reference, IPOJO reference…… Since you are using DS a DS reference is going to be the most convenient.

hope this helps rather than confuses….
david jencks

Paul F Fraser

unread,
Jul 30, 2015, 6:37:13 AM7/30/15
to bndtool...@googlegroups.com
Hi David,

Thanks for your response.

I will try and explain the case again.

Using InstanceMaker from the example quoted below, we create an instance using

Dictionary props = new Hashtable();
props.put("name", "My Name");

config.update(props);

Can the mycomponent code also be used to create instances of a different Class.

For example, I have a core bundle that initiates a user instance. Can the user bundle be used to initiate a banking instance to carry out banking functions for the particular user? Like a chain of instances. Core -> user -> banking

Paul

David Jencks

unread,
Jul 30, 2015, 12:19:07 PM7/30/15
to bndtool...@googlegroups.com
Ok, Well, maybe….. I’m not sure that using config admin is a very appropriate way to solve whatever problem you are working on.

Your MyComponent is only going to be activated if all it’s dependencies are satisfied. As long as it’s been activated, it can do whatever it wants such as creating a configuration in config admin which might result in another component being activated with that configuration. However, from your A > B > C diagram I’d think that you’d want B to have a required C reference which would prevent B being activated so it can create the configuration for C.

Usually services are relatively long-lived and independent of application runtime data, such as a user id. If it’s a service, any thread can get it from the ServiceRegistry. Do you actually need the entire system to be able to access the service for a particular users banking data?

I can think of 2 more usual approaches:

1. Make C a service where C’s methods accept a data object that has the user’s information in it. I.e., C is stateless with regards to the user.

2. Make C a FactoryComponent but not a service. Then B can get a “private” instance of C from the configuration data and explicitly dispose of it when it is done. C can still have DS references to other components. Personally, I’ve never found a reasonable use for this approach, but I haven’t really written “applications” using DS, just server components.

Hope this helps

david jencks

Paul F Fraser

unread,
Jul 31, 2015, 11:37:19 PM7/31/15
to bndtool...@googlegroups.com
Hi David,

Thanks for your input into my deliberations, your comments provided the input needed to put me on
the path to a solution.
It is indeed possible to chain config admin created components, I have had good success with using
the technique now on ds servlets dedicated to a particular user.

Paul
Reply all
Reply to author
Forward
0 new messages