# Can Bnd generate a "factory" service like LoggerFactory?

**URL:** <https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183>\
**Category:** GENERAL\
**Created:** [October 30, 2021, 10:57pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183 "2021-10-30T22:57:06Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [October 30, 2021, 10:57pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/1 "2021-10-30T22:57:06Z")

</div>

Hi,

I have been trying to use Bnd to create a service which can be used like `LoggerFactory` can:

```java
@Reference(service = LoggerFactory.class)
Logger logger;

```

I understand this capability to be [a new feature of DS 1.4](https://blog.osgi.org/2018/03/osgi-r7-highlights-declarative-services.html). However, I am struggling to find the correct combination of instructions to do this. The Felix Log bundle apparently uses a Bundle Activator to register a `ServiceFactory` - both practices which AFAIK are obsolete. The `@Component(serviceFactory=xxx)` element is also deprecated in favour of `scope()`, which suggests it isn’t what I want anyway.

Does Bnd support creating a service that can do this please? Or can it only be achieved through hand-coding inside a Bundle Activator? However, I don’t understand how the Bundle Activator can be the solution either, because Bnd fails when it tries to parse my own factory service `@Reference` annotation with this message:

> error : No interface specified on instance

(where `instance` is the name of my constructor parameter) whereas it parses an equivalent factory reference using `LoggerFactory` without any problem at all 😕.

Thanks for any help here,  
Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [October 31, 2021, 6:39pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/2 "2021-10-31T18:39:11Z")

</div>

> [@chrisr3](#):
>
> I understand this capability to be [a new feature of DS 1.4](https://blog.osgi.org/2018/03/osgi-r7-highlights-declarative-services.html).

DS 1.4 has [special support for LoggerFactory/Logger](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-logger.support) _only_. This support is enabled through special runtime support in Service Component Runtime (along with Bnd not declaring a type mismatch between the field type and the service type).

There is no support in DS for doing this for your own custom service.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [October 31, 2021, 8:34pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/3 "2021-10-31T20:34:54Z")

</div>

Oh, OK. Thanks for replying, although it’s a bit disappointing 😢. However, it occurs to me that I could still register an implementation of `ServiceFactory` via a `Bundle-Activator` though, like the Felix Log bundle does, so that I could write

```java
@Reference
Bongo bongo

```

in the usual way, instead of

```java
@Reference(service = BongoFactory.class)
Bongo bongo

```

My underlying problem being that only `BongoFactory` can be annotated as a `@Component`, although we only really want to use `Bongo` instances.

Does this seem like a worthwhile thing to try please? Or do you think I would only be storing up future pain?

Thanks for any advice,  
Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [October 31, 2021, 8:55pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/4 "2021-10-31T20:55:49Z")

</div>

I am not sure what your actual goal is here. If your goal is to create a new instance of your service component for each bundle consuming the service, which is basically the purpose of ServiceFactory, then just [register your service component](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#d0e38747) with `scope=ServiceScope.BUNDLE`.

```java
@Component(scope=ServiceScope.BUNDLE)
public class BongoImpl implements Bongo {}

```

This tells SCR to create a distinct component instance for each consuming bundle. To know which bundle the component instance is associated with, have the activate method take a `ComponentContext` and its [`getUsingBundle()`](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#org.osgi.service.component.ComponentContext.getUsingBundle--) method will tell you.

Then you don’t need to mess with BundleActivator and ServiceFactory.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [October 31, 2021, 9:01pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/5 "2021-10-31T21:01:50Z")

</div>

Well, the issue is that `Bongo` objects have constructor parameters that are not themselves injectable. I can only inject a `BongoFactory` and then create an new `Bongo` instance.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [October 31, 2021, 9:42pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/6 "2021-10-31T21:42:27Z")

</div>

> [@chrisr3](#):
>
> the issue is that `Bongo` objects have constructor parameters

OK. This is why interface types make better service types than concrete types.

---

<div class="post-metadata">

**Author:** ![kriegfrj](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/kriegfrj/32/24_2.png) [@kriegfrj](https://bnd.discourse.group/u/kriegfrj)\
**Post date:** [November 1, 2021, 7:24am UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/7 "2021-11-01T07:24:15Z")

</div>

👍

Completely coincidentally, I happened to be looking at this exact same issue today. Like @chrisr3, I was excited as I remembered that the Logger/LoggerFactory has exactly this capability. And like @chrisr3, my excitement was short-lived when I discovered that this capability had been hacked into bnd & DS as a special case for Logger/LoggerFactory.

> @bjhargrave  
> OK. This is why interface types make better service types than concrete types.

I don’t think this is relevant. “Logger” is an interface type - you still found it necessary to implement a factory pattern. At the fundamental level, this was necessary because the concrete logger implementation requires construction parameters. In this case, the shorthand can still work because all the necessary parameters (Bundle, type, etc) can be inferred or set to sensible defaults based on the caller context. Then each caller gets a concrete Logger implementation that is tailored for its context. It is not hard to think of other situations where this pattern might also be useful.

In my particular case, I have a webservice client which needs username/password set up during construction. I can determine the username/password required automatically based on caller context. At the moment, I have to inject a factory service and invoke the “newService()” method to generate the actual instance that I want to work on. This is eminently feasible and it works. But being able to use the `@Reference(service=XXX.class)` shorthand would have been neat and would have eliminated this boilerplate (which are presumably the same reasons that this shorthand was introduced for the Logger service in the first place).

Just a thought. There might be valid reasons why this wouldn’t work.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 10:31am UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/8 "2021-11-01T10:31:43Z")

</div>

I have just tried the following:

```auto
@Component(service = [BongoFactory::class])
class BongoFactory @Activate constructor(context: BundleContext) {
    private val registration = context.registerService(arrayOf(Bongo::class.java.name), BongoServiceFactory(), null)

    @Deactivate
    fun done() {
        registration.unregister()
    }

    private inner class BongoServiceFactory : ServiceFactory<Bongo> {
       // etc
    }
}

```

which does at least compile. However, Bnd’s `Resolve` task rejects any attempt to inject

```auto
@Reference
Bongo bongo

```

presumably because my dynamic service registration has no XML metadata 😢. But apart from that, this does seem to work at runtime! Is there any way to get the `Resolve` task still to pass please?

Cheers,  
Chris

P.S. And I’ve just realised that I can annotate `BongoServiceFactory` as a `@Component` too, and suddenly the `Resolve` is happy! Is this legal?

P.P.S. Hmph, I guess it’s _not_ legal as it doesn’t seem to work in the general case.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 2:16pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/9 "2021-11-01T14:16:26Z")

</div>

OK, so _this_ works:

```auto
@Component(service = [BongoFactory::class])
class BongoFactory @Activate constructor(context: BundleContext) {
    private val registration = context.registerService(arrayOf(Bongo::class.java.name), BongoServiceFactory(), null)

    @Deactivate
    fun done() {
        registration.unregister()
    }

    // Provides the XML metadata for the dynamic service registration, to keep Resolve happy.
    @Component(service = [Bongo::class], enabled = false)
    private abstract class DummyBongo : Bongo

    private inner class BongoServiceFactory : ServiceFactory<Bongo> {
       // etc
    }
}

```

I am hoping there is nothing “untoward” about that…

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [November 1, 2021, 2:30pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/10 "2021-11-01T14:30:39Z")

</div>

in Java this pattern is simply:

```java
@Component(service = Bongo.class)
public class BongoFactory implements ServiceFactory<Bongo> {
  public Bongo getService(Bundle bundle, ServiceRegistration<Bongo> reg) {
     return new BongoImpl(par1);
  }
  @Reference
  AnyConstructorParamsToBuildBongoImpl par1;
}

```

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 2:46pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/11 "2021-11-01T14:46:37Z")

</div>

I did try something like this, but Bnd complained that `BongoFactory` was not assignable to `Bongo`. Presumably because it only implements `ServiceFactory<Bongo>` and not `Bongo` itself.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [November 1, 2021, 2:59pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/12 "2021-11-01T14:59:16Z")

</div>

> [@rotty3000](#):
>
> `public class BongoFactory implements ServiceFactory<Bongo>`

This wont work as you hope because DS has no provision for a component class to be the actual ServiceFactory. SCR will always be the service factory and a component class will always be the actual service object.

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [November 1, 2021, 3:01pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/13 "2021-11-01T15:01:08Z")

</div>

right right of course! you need to use the property `@Component.scope` (As you stated) to alter the behaviour of the factory. I should just quit all mondays.

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [November 1, 2021, 3:05pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/14 "2021-11-01T15:05:24Z")

</div>

> [@chrisr3](#):
>
> ```auto
> // Provides the XML metadata for the dynamic service registration, to keep Resolve happy.
> @Component(service = [Bongo::class], enabled = false)
> private abstract class DummyBongo : Bongo
> 
> ```

This may cause the resolver to accept that there is a Bongo service being registered but, in reality, there is no Bongo service being registered. Just a BongoFactory service.

There is no way to “trick” DS and Bnd into doing what you want. DS does not support that. DS was designed to address most common service registration and usage patterns but not all in an effort to avoid making the design too complex. Sometimes you do need to drop back to using the real service API. In your case, where Bongo object creation requires a specific constructor to be called, you will need to author and register your own ServiceFactory.

If Bongo has a default constructor, you could also try a facade approach where the Bongo component class creates a real Bongo object and delegates to it. But if Bongo does not have a default constructor, that is probably not possible.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 3:17pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/15 "2021-11-01T15:17:05Z")

</div>

> In your case, where Bongo object creation requires a specific constructor to be called, you will need to author and register your own ServiceFactory.

Which is what I have done: `BongoFactory` registers `BongoServiceFactory` dynamically when it activates, and unregisters it when it deactivates. However, the whole point of doing this is to allow me to inject `@Reference Bongo` into other services, and the Bnd `Resolve` task apparently cannot satisfy such references unless it can find a matching XML descriptor too.

The `DummyBongo` class only exists to satisfy `Resolve`. `BongoFactory` and `BongoServiceFactory` work fine at runtime without it.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 8:24pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/16 "2021-11-01T20:24:53Z")

</div>

Hmm, thinking about this a bit more… Would it more accurate to have:

```auto
@Component(
    service = [Bongo::class],
    scope = ServiceScope.PROTOTYPE,
    enabled = false
)
private abstract class DummyBongo : Bongo

```

since this service is actually implemented by a dynamic `ServiceFactory`? Or in other words - doesn’t using a `ServiceFactory` automatically imply “prototype” scope?

Just wondering…  
Thanks,  
Chris

---

<div class="post-metadata">

**Author:** ![bjhargrave](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/bjhargrave/32/10_2.png) [@bjhargrave](https://bnd.discourse.group/u/bjhargrave)\
**Post date:** [November 1, 2021, 8:45pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/17 "2021-11-01T20:45:05Z")

</div>

> [@chrisr3](#):
>
> Would it more accurate to have:

That service does not exist. You are just getting Bnd to put an xml descriptor in the jar file to convince the resolver that there is a provider of the Bongo service. So it is basically irrelevant what the xml descriptor says beyond that it provides a Bongo service.

In reality, no Bongo service is provided at runtime in the OSGi Service Registry. There is only a BongoFactory service. Any `Reference` to the Bongo service will not be satisfied (your dummy bongo is not enabled and if it was enabled, it would be the supplied Bongo service).

The resolver issue is pointing out the problem (there is no Bongo provider) which you seem to want to wallpaper over with an xml descriptor for a disabled service.

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 9:12pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/18 "2021-11-01T21:12:37Z")

</div>

At the very least, I was thinking that adding `scope = PROTOTYPE` would serve as documentation for how the implementation behaves at runtime: it satisfies `Bongo` references with the output of my dynamically registered `ServiceFactory<Bongo>`.

> In reality, no Bongo service is provided at runtime in the OSGi Service Registry.

Well, not until the `BongoFactory` service activates and then registers a `Bongo` service. Doesn’t `BundleContest.registerService()` add something to the OSGi Service Registry?

Edit: _Aha!_ I’ve just read the Javadocs for `Constants.SCOPE_PROTOTYPE`… So my `Bongo` service actually has `BUNDLE` scope, unless I implement `PrototypeServiceFactory` instead.

---

<div class="post-metadata">

**Author:** ![rotty3000](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/rotty3000/32/16_2.png) [@rotty3000](https://bnd.discourse.group/u/rotty3000)\
**Post date:** [November 1, 2021, 9:30pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/19 "2021-11-01T21:30:05Z")

</div>

Doesn’t DS 1.4’s support for constructor injection address the concerns of this topic?

```auto
@Component(scope = PROTOTYPE, service = Bongo.class)
public class BongoImpl {
   @Activate
   public BongoImpl(BundleContext bundleContext, @Reference Foo foo) {
       ...
   }
}

```

---

<div class="post-metadata">

**Author:** ![chrisr3](https://yyz2.discourse-cdn.com/free1/user_avatar/bnd.discourse.group/chrisr3/32/58_2.png) [@chrisr3](https://bnd.discourse.group/u/chrisr3)\
**Post date:** [November 1, 2021, 9:31pm UTC](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183/20 "2021-11-01T21:31:09Z")

</div>

Only if `Foo` is also a `@Component`, which is not true for my case.

[Next page](https://bnd.discourse.group/t/can-bnd-generate-a-factory-service-like-loggerfactory/183.md?page=2)
